#!python3
# -*- coding: utf-8 -*-

"""
@author: Heanny
@contact: lzh@heanny.cn
@site:
@software: PyCharm
@file: music.py
@time: 2018/8/8 16:15
"""
import requests, json
import random, math
from Crypto.Cipher import AES
import base64
import codecs
import os

"""
获取歌曲地址：https://music.XXX.com/weapi/song/enhance/player/url?csrf_token=429d8812f4449bb9acb60e7647113999
"""


class Spider(object):
	def __init__(self):
		self.headers = {
			'Accept': '*/*',
			'Accept-Encoding': 'gzip, deflate, sdch',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6',
			'Connection': 'keep-alive',
			'Content-Type': 'application/x-www-form-urlencoded',
			'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
			'Cookie': '_ntes_nnid=2da511387474575b77a1e0a13d6df57e,1527507977129; _ntes_nuid=2da511387474575b77a1e0a13d6df57e; vinfo_n_f_l_n3=2e40f7fc7366d16d.1.0.1527507977156.0.1527508882506; usertrack=ezq0plswU1Wdn48dA1XZAg==; _ga=GA1.2.660826221.1529893720; __f_=1532395985802; _iuqxldmzr_=32; __utmz=94650624.1534308847.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); WM_TID=Z1Jm%2FrA9KHL%2BHxOBomtGeqTrwVoLDJtd; __utmc=94650624; playerid=19834031; JSESSIONID-WYYY=xMEDtoZO%2BiRzkY3QR%5ChVyupwUBwFivY%2BBAyCPJNlEcmafmm94pa%2BquYglywlQBWN4gKk90XO0Dlx1JCU%2BJ3CmBnV8jHBu5Rzj%2BE%5CcvpBRf%2B%2FI%2BUx71SY5lEsfeJKD6SpzZNCw%2Bae%5Ccnl%5CGv7diN8FZ3Hshs6Bh9Aiooh6sjZkafmwztx%3A1534325997512; __utma=94650624.660826221.1529893720.1534319610.1534324198.4; __utmb=94650624.2.10.1534324198; WM_NI=ZzfxoKxGKsmy3YW9fXsRoCollXv7f8VCQELJt4javuXbEgmayUVzE2FcppvHW174lpq1iEeIUNhLS69AeEf%2B%2Fsf5BGaLSIbLfmBZDUozXUnTXRxo2%2BpZmH79ev2gI8%2FqdTI%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eeb5ec398bbcbaa8f3549aeaa494e763938aa68dc952f68d8585b77aba95b8baf22af0fea7c3b92a9aa6aa99ee41bc998594f073f18799dae554b18ea1a4ee68b088bad8e534969d9fa6cf42b8eca682f57f9cbe8b88f06bbb8b9a9bc83a86bdc091f54495eff9d5ef7cb3efa7a6e8439792a8add23efb9faba6e521edadaad6c14da3949daae148a6b38ebbc75fada698b6ed609c8eb890b121b486a3a9b633a7aafe88cc34edafacb5cc37e2a3'
		}

	def __get_songs(self, name):
		d = json.dumps(
			{"hlpretag": "<span class=\"s-fc7\">", "hlposttag": "</span>", "s": name, "type": "1", "offset": "0",
			 "total": True, "limit": 30, "csrf_token": ""})
		wyy = WangYiYun(d)  # 要搜索的歌曲名在这里
		data = wyy.get_data()
		url = 'https://music.XXX.com/weapi/cloudsearch/get/web?csrf_token='
		response = requests.post(url, data=data, headers=self.headers).json()
		return response['result']

	def __get_mp3(self, id):
		d = json.dumps({'ids': "[{}]".format(id), 'br': 320000, 'csrf_token': ""})
		wyy = WangYiYun(d)
		data = wyy.get_data()
		url = 'https://music.XXX.com/weapi/song/enhance/player/url?csrf_token='
		response = requests.post(url, data=data, headers=self.headers).json()
		print(response['code'])
		if response['code'] == -460:
			return ''
		return response['data'][0]['url']

	def __download_mp3(self, url, filename):
		"""下载mp3"""
		abspath = os.path.abspath('.')  # 获取绝对路径
		os.chdir(abspath)
		response = requests.get(url, headers=self.headers).content
		path = os.path.join(abspath, filename)
		with open('{}.mp3'.format(filename), 'wb') as f:
			f.write(response)
		print('下载完毕,可以在{}.mp3查看'.format(path))

	def __print_info(self, songs):
		"""打印歌曲需要下载的歌曲信息"""
		songs_list = []
		for num, song in enumerate(songs):
			print(num, '歌曲名字：', song['name'], '作者：', song['ar'][0]['name'])
			songs_list.append((song['name'], song['id']))
		return songs_list

	def run(self):
		while True:
			name = input('请输入你需要下载的歌曲：')
			songs = self.__get_songs(name)
			if songs['songCount'] == 0:
				print('没有搜到此歌曲，请换个关键字')
			else:
				songs = self.__print_info(songs['songs'])
				num = input('请输入需要下载的歌曲，输入左边对应数字即可')
				if num == 'q':
					pass
				else:
					url = self.__get_mp3(songs[int(num)][1])
					if not url:
						print('歌曲需要收费，下载失败')
					else:
						filename = songs[int(num)][0]
						self.__download_mp3(url, filename)
					flag = input('如需继续可以按任意键进行搜歌，否则按0结束程序')
					if flag == '0':
						break
		print('程序结束！')


class WangYiYun(object):
	def __init__(self, d):
		self.d = d
		self.e = '010001'
		self.f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5a" \
		         "a76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46be" \
		         "e255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
		self.g = "0CoJUm6Qyw8W8jud"
		self.random_text = self.get_random_str()

	def get_random_str(self):
		"""js中的a函数"""
		str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
		res = ''
		for x in range(16):
			index = math.floor(random.random() * len(str))
			res += str[index]
		return res

	def aes_encrypt(self, text, key):
		iv = '0102030405060708'  # 偏移量
		pad = 16 - len(text.encode()) % 16  # 使加密信息的长度为16的倍数，要不会报下面的错
		# 长度是16的倍数还会报错，不能包含中文，要对他进行unicode编码
		text = text + pad * chr(pad)  # Input strings must be a multiple of 16 in length
		encryptor = AES.new(key, AES.MODE_CBC, iv)
		msg = base64.b64encode(encryptor.encrypt(text))  # 最后还需要使用base64进行加密
		return msg

	def rsa_encrypt(self, value, text, modulus):
		'''进行rsa加密'''
		text = text[::-1]
		rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(value, 16) % int(modulus, 16)
		return format(rs, 'x').zfill(256)

	def get_data(self):
		# 这个参数加密两次
		params = self.aes_encrypt(self.d, self.g)
		params = self.aes_encrypt(params.decode('utf-8'), self.random_text)
		enc_sec_key = self.rsa_encrypt(self.e, self.random_text, self.f)
		return {
			'params': params,
			'encSecKey': enc_sec_key
		}


def main():
	spider = Spider()
	spider.run()


if __name__ == '__main__':
	main()
